/**
 * Desc: NodeJS标准输入/输出流的包装器
 * Func: 1.将按键事件转换为内核程序需要的格式。
 *       2.将输出函数包装成内核程序需要的接口。
 */
import readline from "node:readline";

/**
 * 按键代码映射(NodeJS标准=>Web标准)
 */
const keyMap = (function () {
    const map = new Map();
    // 功能键
    map.set("left", "ArrowLeft");
    map.set("right", "ArrowRight");
    map.set("up", "ArrowUp");
    map.set("down", "ArrowDown");
    map.set("backspace", "Backspace");
    map.set("return", "Enter");
    map.set("escape", "Escape");
    // 空格键
    map.set(" ", "Space");
    // 数字键
    map.set("0", "Digit0");
    map.set("1", "Digit1");
    map.set("2", "Digit2");
    map.set("3", "Digit3");
    map.set("4", "Digit4");
    map.set("5", "Digit5");
    map.set("6", "Digit6");
    map.set("7", "Digit7");
    map.set("8", "Digit8");
    map.set("9", "Digit9");
    // 字母键
    map.set("a", "KeyA");
    map.set("b", "KeyB");
    map.set("c", "KeyC");
    map.set("d", "KeyD");
    map.set("e", "KeyE");
    map.set("f", "KeyF");
    map.set("g", "KeyG");
    map.set("h", "KeyH");
    map.set("i", "KeyI");
    map.set("j", "KeyJ");
    map.set("k", "KeyK");
    map.set("l", "KeyL");
    map.set("m", "KeyM");
    map.set("n", "KeyN");
    map.set("o", "KeyO");
    map.set("p", "KeyP");
    map.set("q", "KeyQ");
    map.set("r", "KeyR");
    map.set("s", "KeyS");
    map.set("t", "KeyT");
    map.set("u", "KeyU");
    map.set("v", "KeyV");
    map.set("w", "KeyW");
    map.set("x", "KeyX");
    map.set("y", "KeyY");
    map.set("z", "KeyZ");

    return map;
})();

/**
 * 定义清屏代码
 */
const CLS_KEYWORD = process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H';

// 配置NodeJS通过readline发送KeyPress事件
readline.emitKeypressEvents(process.stdin);
if (process.stdin.isTTY) {
    process.stdin.setRawMode(true);
}

/**
 * 监听器集合
 */
const listenerSet = new Set();
/**
 * 按键事件转发函数
 * @param {string} char 
 * @param {string} key 
 */
const onKeyPress = (char, key) => {
    // 按键代码转换
    let keyCode;
    if (keyMap.has(key.name)) {
        keyCode = keyMap.get(key.name);
    } else {
        keyCode = key.name;
    }
    // 构造新键盘事件
    const keyEvent = {
        data: char,
        code: keyCode,
        ctrlKey: key.ctrl,
        shiftKey: key.shift,
        altKey: key.alt,
        metaKey: key.mata
    };
    // 派发事件
    for (const listener of listenerSet.values()) {
        listener.call(null, keyEvent);
    }
};

/**
 * 更新输入流信号连接
 */
function updateStdinKeyConnection() {
    if (listenerSet.size > 0) {
        if (process.stdin.listeners("keypress").includes(onKeyPress) === false) {
            process.stdin.on("keypress", onKeyPress);
        }
    } else {
        if (process.stdin.listeners("keypress").includes(onKeyPress)) {
            process.stdin.off("keypress", onKeyPress);
        }
    }
}

/**
 * 退出前的处理
 */
process.on('beforeExit', (code) => {
    listenerSet.clear();
    updateStdinKeyConnection();
});

/**
 * 定义新的输入流
 */
export const inputStream = {
    addKeyPressListener: (callback) => {
        if (listenerSet.has(callback) === false) {
            listenerSet.add(callback);
            updateStdinKeyConnection();
        }
    },
    removeKeyPressListener: (callback) => {
        if (listenerSet.has(callback)) {
            listenerSet.delete(callback);
            updateStdinKeyConnection();
        }
    }
};

/**
 * 定义新的输出流
 */
export const outputStream = {
    clear: () => {
        process.stdout.write(CLS_KEYWORD);
    },
    write: (content) => {
        process.stdout.write(content);
    },
    update: (content) => {
        process.stdout.write(CLS_KEYWORD + content);
    }
};
